{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Can two-dimensional topological voids exist in two dimensions?\n",
    "\n",
    "The classic example of a two-dimensional homology class is the \"void\" surrounded by a sphere in three-dimensional space.\n",
    "Challenge question: **Can two-dimensional topological voids arise from point clouds in two-dimensional space?**\n",
    "We will answer this question programmatically by computing Vietoris–Rips persistent homology of random point clouds in the square $[0, 1] \\times [0, 1] \\subset \\mathbb{R}^2$.\n",
    "\n",
    "If you are looking at a static version of this notebook and would like to run its contents, head over to [GitHub](https://github.com/giotto-ai/giotto-tda/blob/master/examples/voids_on_the_plane.ipynb) and download the source.\n",
    "\n",
    "**License: AGPLv3**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from gtda.homology import VietorisRipsPersistence\n",
    "import itertools\n",
    "\n",
    "import matplotlib.pyplot as plt  # Not a requirement of giotto-tda, but is needed here\n",
    "\n",
    "np.random.seed(1)  # Set numpy's random seed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the Vietoris–Rips transformer\n",
    "VR = VietorisRipsPersistence(homology_dimensions=(2,), max_edge_length=np.inf)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create n_samples point clouds of n_points points\n",
    "n_samples = 15000\n",
    "n_points = 6\n",
    "point_clouds = np.random.random((n_samples, n_points, 2))\n",
    "\n",
    "# Compute persistence diagrams of all point clouds\n",
    "diags = VR.fit_transform(point_clouds)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "diffs = np.nan_to_num(diags[:, :, 1] - diags[:, :, 0])  # Compute lifetimes\n",
    "indices = np.argwhere(diffs != 0)  # Indices with non-zero lifetime\n",
    "print(f'There are {len(indices[:, 0])} persistent homology classes in dimension 2 across all samples.')\n",
    "print(f'There are {len(np.unique(indices[:, 0]))} different point clouds with at least one persistent homology class in dimension 2.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now plot the edges which exist when these persistent homology classes are born.\n",
    "What do the clique complexes of the resulting graphs remind you of?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in indices[:, 0]:\n",
    "    for e in itertools.combinations(point_clouds[i], 2):\n",
    "        if np.linalg.norm(e[0] - e[1]) < diags[i, 0, 1] - 0.00001:\n",
    "            edge = np.stack([e[0], e[1]])\n",
    "            plt.plot(edge[:, 0], edge[:, 1])\n",
    "    plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
